package com.yupao.service.impl;



import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yupao.common.UserConstant;
import com.yupao.exception.BusinessException;
import com.yupao.mapper.UserMapper;
import com.yupao.model.entity.User;
import com.yupao.model.enums.ErrorCode;
import com.yupao.model.vo.LoginUserVO;
import com.yupao.model.vo.UserVO;
import com.yupao.service.UserService;
import com.yupao.utils.AlgorithmUtil;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    @Resource
    private UserMapper userMapper;

    @Override
    public User getLoginUser(HttpServletRequest request) {

        //从登录态中取出登录用户信息
        User user = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);

        //判断用户是否登录
        if (user == null || user.getId() == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        //判断是否存在数据库中
        user = this.getById(user.getId());
        if (user == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        return user;
    }


    @Override
    public User getSafetyUser(User originUser) {
        if (ObjectUtils.isEmpty(originUser)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        User safetyUser = new User();
        safetyUser.setId(originUser.getId());
        safetyUser.setUsername(originUser.getUsername());
        safetyUser.setUserAccount(originUser.getUserAccount());
        safetyUser.setAvatarUrl(originUser.getAvatarUrl());
        safetyUser.setGender(originUser.getGender());
        safetyUser.setPhone(originUser.getPhone());
        safetyUser.setEmail(originUser.getEmail());
        safetyUser.setPlanetCode(originUser.getPlanetCode());
        safetyUser.setUserRole(originUser.getUserRole());
        safetyUser.setUserStatus(originUser.getUserStatus());
        safetyUser.setCreateTime(originUser.getCreateTime());
        safetyUser.setTags(originUser.getTags());
        return safetyUser;
    }

    @Override
    public Boolean isAdmin(LoginUserVO user) {
        return user != null && UserConstant.USER_ADMIN.equals(user.getUserRole());
    }

    @Override
    public Boolean isAdmin(HttpServletRequest request) {
        User loginUser = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        return loginUser!= null && UserConstant.USER_ADMIN.equals(loginUser.getUserRole());
    }

    @Override
    public LoginUserVO getLoginUser() {

        //从session中拿到用户信息
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        User currentLoginUser = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        if (ObjectUtils.isEmpty(currentLoginUser) || currentLoginUser.getId() == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        //判断数据库中是否存在
        Long id = currentLoginUser.getId();
        User user = this.getById(id);
        if (ObjectUtils.isEmpty(user)) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "该用户未注册");
        }

        //转换成安全用户
        LoginUserVO loginUserVO = new LoginUserVO();
        BeanUtils.copyProperties(currentLoginUser, loginUserVO);

        //返回安全用户
        return loginUserVO;
    }

    @Override
    public Integer updateUser(User user) {
        //非空
        if (ObjectUtils.isEmpty(user)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //判断修改用户是否存在
        Long userId = user.getId();
        User updateUser = userMapper.selectById(userId);
        if (ObjectUtils.isEmpty(updateUser)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //获得当前用户
        LoginUserVO loginUser = this.getLoginUser();

        //鉴权  管理员和当前登录用户
        if (!Objects.equals(user.getId(), loginUser.getId()) && isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }

        int result = userMapper.updateById(user);

        //如果修改的是当前用户及时更改session用户态中的信息
        if (Objects.equals(user.getId(), loginUser.getId())) {
            User longinUser = userMapper.selectById(user.getId());
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, longinUser);
        }

        //修改用户
        return result;
    }

    @Override
    public List<User> searchUserByTags(List<String> tagList) {

        /*//根据sql查询用户
        //非空判断
        if (CollectionUtils.isEmpty(tagList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //条件构造器
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        for (String tag : tagList) {
            queryWrapper = queryWrapper.like(User::getTags, tag);
        }

        //查询
        List<User> userList = userMapper.selectList(queryWrapper);
        return userList.stream().map(this::getSafetyUser).collect(Collectors.toList());*/

        //根据内存查询
        //把全部用户数据查询出来
        //非空判单
        if (CollectionUtils.isEmpty(tagList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //无条件查询，把所有数据都查询出来
        List<User> userList = userMapper.selectList(queryWrapper);
        //过滤
        List<User> safetyUserList = userList.stream().filter(
                user -> {
                    String tags = user.getTags();
                    if (StringUtils.isEmpty(tags)) {
                        return false;
                    }
                    Gson gson = new Gson();
                    Set<String> tagSet = gson.fromJson(tags, new TypeToken<Set<String>>() {
                    }.getType());
                    for (String tag : tagList) {
                        if (tagSet.contains(tag)) {
                            return true;
                        }
                    }
                    return false;
                }
        ).map(this::getSafetyUser).collect(Collectors.toList());


        return safetyUserList;


    }

    @Override
    public LoginUserVO userLogin(String userAccount, String userPassword) {
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //特殊字符校验
        String vaildPattern = "^[a-zA-Z0-9_]{4,}$";
        boolean matches = Pattern.compile(vaildPattern).matcher(userAccount).matches();
        if (!matches) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 账号
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //密码
        if (userPassword.length() < 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String md5Password = DigestUtils.md5DigestAsHex(userPassword.getBytes());
        //判断用户是否存在
        User user = this.lambdaQuery()
                .eq(User::getUserAccount, userAccount)
                .eq(User::getUserPassword, md5Password)
                .one();

        if (ObjectUtils.isEmpty(user)) {
            log.info("user login failed, userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //记录用户的登录态
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);

        //转化成VO返回
        LoginUserVO loginUserVO = new LoginUserVO();
        BeanUtils.copyProperties(user, loginUserVO);

        return loginUserVO;
    }

    @Override
    public Long userRegister(String userAccount, String userPassword) {
        //非空判断
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //账号特殊字符
        String vaildPattern = "^[a-zA-Z0-9_]{4,}$";
        boolean matches = Pattern.compile(vaildPattern).matcher(userAccount).matches();
        if (!matches) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //账号密码长度
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (userPassword.length() < 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //账号名称是否重复
        User user = this.lambdaQuery().eq(User::getUserAccount, userAccount).one();
        if (ObjectUtils.isNotEmpty(user)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //加密密码
        String md5Password = DigestUtils.md5DigestAsHex(userPassword.getBytes());

        //插入数据
        User insertUser = new User();
        insertUser.setUserAccount(userAccount);
        insertUser.setUserPassword(md5Password);
        boolean saveResult = this.save(insertUser);
        if (!saveResult) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        Long userId = insertUser.getId();
        return userId;
    }

    @Override
    public List<UserVO> matchUsers(long num) {
        if (num <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        /*
            1.获得登录用户的信息
            2.根据条件查询所有用户 List
            3.遍历所用用户 使用算法 计算用户和查询用户的最短距离 Map List<Pair<User, Distance>>
                a.过滤掉标签为空和自己
            4.使用stream流获得前5个对象
         */

        //1.获得当前登录用户的信息
        LoginUserVO loginUser = this.getLoginUser();
        String loginUserTags = loginUser.getTags();
        Gson gson = new Gson();
        List<String> loginUserTagList = gson.fromJson(loginUserTags, new TypeToken<List<String>>() {
        }.getType());

        //2.根据条件查询所有用户 List
        List<User> userList = this.lambdaQuery()
                .isNotNull(User::getTags)
                .list();

        //3.遍历所用用户 使用算法 计算用户和查询用户的最短距离 Map List<Pair<User, Distance>>
        List<Pair<User, Integer>> list = new ArrayList<>();
        for (User user : userList) {
            String tags = user.getTags();
            if (StringUtils.isBlank(tags) || Objects.equals(user.getId(), loginUser.getId())) {
                continue;
            }
            List<String> tagList = gson.fromJson(tags, new TypeToken<List<String>>() {
            }.getType());
            int distance = AlgorithmUtil.minDistance(loginUserTagList, tagList);
            list.add(new Pair<>(user, distance));
        }

        //4.使用stream流获得前5个对象
        List<User> orderUserList = list.stream()
                .sorted(((o1, o2) -> o1.getValue().compareTo(o2.getValue())))
                .limit(5)
                .map(Pair::getKey)
                .collect(Collectors.toList());

        List<UserVO> orderUserVOList = new ArrayList<>();
        for (User user : orderUserList) {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            orderUserVOList.add(userVO);
        }

        return orderUserVOList;
    }
}
